package ks.client.game;


import heineman.Idiot;
import heineman.Klondike;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Properties;

import scaviola.BCastle;
import sudoku.Sudoku;

import darrent.FreeCell;
import dijordan.PyramidGame;

import brlandry.GrandfatherClock;

import wordsteal.Wordsteal;
import yostinso.FlowerGarden;

import kdaquila.Spider;
import ks.client.game.solitaire.SolitaireGameInformation;
import ks.client.game.sudoku.SudokuGameInformation;
import ks.client.game.wordsteal.WordstealGameInformation;
import ks.common.games.Solitaire;

public class Factory {

	/** Known game types. Constructed the first time validGameTypes is invoked. */
	static ArrayList<String> gameTypes = null;

	/** Known solitaire variations. */
	static ArrayList<String> solitaireVariations = null;

	/**
	 * Determine whether gameType is solitaire.
	 */
	public static boolean isSolitaire(String gameType) {
		if (solitaireVariations == null) {

			solitaireVariations = new ArrayList<String>();

			solitaireVariations.add(GrandfatherClock.class.getCanonicalName());
			solitaireVariations.add(FreeCell.class.getCanonicalName());
			solitaireVariations.add(PyramidGame.class.getCanonicalName());
			solitaireVariations.add(Idiot.class.getCanonicalName());
			solitaireVariations.add(Klondike.class.getCanonicalName());
			solitaireVariations.add(Spider.class.getCanonicalName());
			solitaireVariations.add(BCastle.class.getCanonicalName());
			solitaireVariations.add(FlowerGarden.class.getCanonicalName());
		}
		
		return solitaireVariations.contains(gameType);
	}

	/**
	 * Determine whether gameType is wordsteal.
	 */
	public static boolean isWordSteal(String gameType) {
		return Wordsteal.class.getCanonicalName().equals(gameType);
	}
	
	public static boolean isSudoku(String gameType) {
		return Sudoku.class.getCanonicalName().equals(gameType);
	}

	/** 
	 * Return the set of valid game types supported by this factory.
	 * 
	 * @return
	 */
	public static Iterator<String> validGameTypes() {
		if (gameTypes == null) { 
			gameTypes = new ArrayList<String>();

			// wordsteal
			gameTypes.add(Wordsteal.class.getCanonicalName());

			// solitaire
			gameTypes.add(GrandfatherClock.class.getCanonicalName());
			gameTypes.add(FreeCell.class.getCanonicalName());
			gameTypes.add(PyramidGame.class.getCanonicalName());
			gameTypes.add(Idiot.class.getCanonicalName());
			gameTypes.add(Klondike.class.getCanonicalName());
			gameTypes.add(Spider.class.getCanonicalName());
			gameTypes.add(BCastle.class.getCanonicalName());
			gameTypes.add(FlowerGarden.class.getCanonicalName());
			
			// sudoku
			gameTypes.add(Sudoku.class.getCanonicalName());
		}

		return gameTypes.iterator();
	}

	/**
	 * Construct an object representing the specific Game information
	 * The options parameter must have a 'game' property that represents
	 * the desired game to construct. Valid values for this string
	 * are returned by the {@link #validGameTypes()} method.
	 * <p>
	 * Properties should also have a 'seed' attribute to determine
	 * the random seed to use for the game.
	 * <p>
	 * If the game attribute is missing or incorrect, then null is returned.
	 *  
	 * @param options      Standard options for game (game, seed)
	 * @param gameOptions  Game-specific options for game
	 * @return object that serves to store all game-specific information.
	 * @exception          IllegalArgumentException if game is invalid or missing
	 */
	public static GameInformation create(Properties options, Properties gameOptions) throws IllegalArgumentException {
		String gameName = options.getProperty("game");

		Class<?> c = null;
		try {
			c = Class.forName(gameName);
		} catch (Exception e) {
			throw new IllegalArgumentException ("Unable to create game for unknown type: "+ gameName);
		}

		// see if this class is a solitaire variation
		if (Solitaire.class.isAssignableFrom(c)) {
			return new SolitaireGameInformation (options, gameOptions);
		}

		if (Wordsteal.class.isAssignableFrom(c)) {
			return new WordstealGameInformation (options, gameOptions);
		}

		if (Sudoku.class.isAssignableFrom(c)) {
			return new SudokuGameInformation (options, gameOptions);
		}
		
		throw new IllegalArgumentException ("Invalid game type: "+ gameName);
	}

	
}
